home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / Filezilla Server / FileZilla_Server-0_9_41.exe / source / Options.cpp < prev    next >
C/C++ Source or Header  |  2012-02-22  |  33KB  |  1,366 lines

  1. // FileZilla Server - a Windows ftp server
  2.  
  3. // Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. // Options.cpp: Implementierungsdatei
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include "options.h"
  24. #include "platform.h"
  25. #include "version.h"
  26. #include "tinyxml/tinyxml.h"
  27. #include "iputils.h"
  28. #include "OptionLimits.h"
  29.  
  30. #ifdef _DEBUG
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34.  
  35. std::list<COptions *> COptions::m_InstanceList;
  36. CCriticalSectionWrapper COptions::m_Sync;
  37. COptions::t_OptionsCache COptions::m_sOptionsCache[OPTIONS_NUM];
  38. BOOL COptions::m_bInitialized=FALSE;
  39.  
  40. SPEEDLIMITSLIST COptions::m_sSpeedLimits[2];
  41.  
  42. /////////////////////////////////////////////////////////////////////////////
  43. // COptionsHelperWindow
  44.  
  45. class COptionsHelperWindow
  46. {
  47. public:
  48.     COptionsHelperWindow(COptions *pOptions)
  49.     {
  50.         ASSERT(pOptions);
  51.         m_pOptions=pOptions;
  52.  
  53.         //Create window
  54.         WNDCLASSEX wndclass;
  55.         wndclass.cbSize=sizeof wndclass;
  56.         wndclass.style=0;
  57.         wndclass.lpfnWndProc=WindowProc;
  58.         wndclass.cbClsExtra=0;
  59.         wndclass.cbWndExtra=0;
  60.         wndclass.hInstance=GetModuleHandle(0);
  61.         wndclass.hIcon=0;
  62.         wndclass.hCursor=0;
  63.         wndclass.hbrBackground=0;
  64.         wndclass.lpszMenuName=0;
  65.         wndclass.lpszClassName=_T("COptions Helper Window");
  66.         wndclass.hIconSm=0;
  67.  
  68.         RegisterClassEx(&wndclass);
  69.  
  70.         m_hWnd=CreateWindow(_T("COptions Helper Window"), _T("COptions Helper Window"), 0, 0, 0, 0, 0, 0, 0, 0, GetModuleHandle(0));
  71.         ASSERT(m_hWnd);
  72.         SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG)this);
  73.     };
  74.  
  75.     virtual ~COptionsHelperWindow()
  76.     {
  77.         //Destroy window
  78.         if (m_hWnd)
  79.         {
  80.             DestroyWindow(m_hWnd);
  81.             m_hWnd=0;
  82.         }
  83.     }
  84.  
  85.     HWND GetHwnd()
  86.     {
  87.         return m_hWnd;
  88.     }
  89.  
  90. protected:
  91.     static LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  92.     {
  93.         if (message==WM_USER)
  94.         {
  95.             COptionsHelperWindow *pWnd=(COptionsHelperWindow *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  96.             if (!pWnd)
  97.                 return 0;
  98.             ASSERT(pWnd);
  99.             ASSERT(pWnd->m_pOptions);
  100.             for (int i=0;i<OPTIONS_NUM;i++)
  101.                 pWnd->m_pOptions->m_OptionsCache[i].bCached = FALSE;
  102.             EnterCritSection(COptions::m_Sync);
  103.             pWnd->m_pOptions->m_SpeedLimits[0] = COptions::m_sSpeedLimits[0];
  104.             pWnd->m_pOptions->m_SpeedLimits[1] = COptions::m_sSpeedLimits[1];
  105.             LeaveCritSection(COptions::m_Sync);
  106.         }
  107.         return ::DefWindowProc(hWnd, message, wParam, lParam);
  108.     }
  109.     COptions *m_pOptions;
  110.  
  111. private:
  112.     HWND m_hWnd;
  113. };
  114.  
  115. /////////////////////////////////////////////////////////////////////////////
  116. // Dialogfeld COptions
  117.  
  118. COptions::COptions()
  119. {
  120.     for (int i=0;i<OPTIONS_NUM;i++)
  121.         m_OptionsCache[i].bCached=FALSE;
  122.     m_pOptionsHelperWindow=new COptionsHelperWindow(this);
  123.     EnterCritSection(m_Sync);
  124. #ifdef _DEBUG
  125.     for (std::list<COptions *>::iterator iter=m_InstanceList.begin(); iter!=m_InstanceList.end(); iter++)
  126.         ASSERT(*iter!=this);
  127. #endif _DEBUG
  128.     m_InstanceList.push_back(this);
  129.     m_SpeedLimits[0] = m_sSpeedLimits[0];
  130.     m_SpeedLimits[1] = m_sSpeedLimits[1];
  131.     LeaveCritSection(m_Sync);
  132. }
  133.  
  134. COptions::~COptions()
  135. {
  136.     EnterCritSection(m_Sync);
  137.     std::list<COptions *>::iterator iter;
  138.     for (iter=m_InstanceList.begin(); iter!=m_InstanceList.end(); iter++)
  139.         if (*iter==this)
  140.             break;
  141.  
  142.     ASSERT(iter!=m_InstanceList.end());
  143.     if (iter != m_InstanceList.end())
  144.         m_InstanceList.erase(iter);
  145.     LeaveCritSection(m_Sync);
  146.  
  147.     if (m_pOptionsHelperWindow)
  148.         delete m_pOptionsHelperWindow;
  149.     m_pOptionsHelperWindow=0;
  150. }
  151.  
  152. void COptions::SetOption(int nOptionID, _int64 value, bool save /*=true*/)
  153. {
  154.     switch (nOptionID)
  155.     {
  156.     case OPTION_MAXUSERS:
  157.         if (value<0)
  158.             value=0;
  159.         break;
  160.     case OPTION_THREADNUM:
  161.         if (value<1)
  162.             value=2;
  163.         else if (value>50)
  164.             value=2;
  165.         break;
  166.     case OPTION_TIMEOUT:
  167.         if (value<0)
  168.             value=120;
  169.         else if (value>9999)
  170.             value=120;
  171.         break;
  172.     case OPTION_NOTRANSFERTIMEOUT:
  173.         if (value<600 && value != 0)
  174.             value=600;
  175.         else if (value>9999)
  176.             value=600;
  177.         break;
  178.     case OPTION_LOGINTIMEOUT:
  179.         if (value<0)
  180.             value=60;
  181.         else if (value>9999)
  182.             value=60;
  183.         break;
  184.     case OPTION_ADMINPORT:
  185.         if (value>65535)
  186.             value=14147;
  187.         else if (value<1)
  188.             value=14147;
  189.         break;
  190.     case OPTION_LOGTYPE:
  191.         if (value!=0 && value!=1)
  192.             value = 0;
  193.         break;
  194.     case OPTION_LOGLIMITSIZE:
  195.         if ((value > 999999 || value < 10) && value!=0)
  196.             value = 100;
  197.         break;
  198.     case OPTION_LOGDELETETIME:
  199.         if (value > 999 || value < 0)
  200.             value = 14;
  201.         break;
  202.     case OPTION_DOWNLOADSPEEDLIMITTYPE:
  203.     case OPTION_UPLOADSPEEDLIMITTYPE:
  204.         if (value < 0 || value > 2)
  205.             value = 0;
  206.         break;
  207.     case OPTION_DOWNLOADSPEEDLIMIT:
  208.     case OPTION_UPLOADSPEEDLIMIT:
  209.         if (value < 1)
  210.             value = 1;
  211.         else if (value > 1048576)
  212.             value = 1048576;
  213.         break;
  214.     case OPTION_BUFFERSIZE:
  215.         if (value < 256 || value > (1024*1024))
  216.             value = 32768;
  217.         break;
  218.     case OPTION_BUFFERSIZE2:
  219.         if (value < 256 || value > (1024*1024*128))
  220.             value = 262144;
  221.         break;
  222.     case OPTION_CUSTOMPASVIPTYPE:
  223.         if (value < 0 || value > 2)
  224.             value = 0;
  225.         break;
  226.     case OPTION_MODEZ_USE:
  227.         if (value < 0 || value > 1)
  228.             value = 0;
  229.         break;
  230.     case OPTION_MODEZ_LEVELMIN:
  231.         if (value < 0 || value > 8)
  232.             value = 1;
  233.         break;
  234.     case OPTION_MODEZ_LEVELMAX:
  235.         if (value < 8 || value > 9)
  236.             value = 9;
  237.         break;
  238.     case OPTION_MODEZ_ALLOWLOCAL:
  239.         if (value < 0 || value > 1)
  240.             value = 0;
  241.         break;
  242.     case OPTION_AUTOBAN_ATTEMPTS:
  243.         if (value < OPTION_AUTOBAN_ATTEMPTS_MIN)
  244.             value = OPTION_AUTOBAN_ATTEMPTS_MIN;
  245.         if (value > OPTION_AUTOBAN_ATTEMPTS_MAX)
  246.             value = OPTION_AUTOBAN_ATTEMPTS_MAX;
  247.         break;
  248.     case OPTION_AUTOBAN_BANTIME:
  249.         if (value < 1)
  250.             value = 1;
  251.         if (value > 999)
  252.             value = 999;
  253.         break;
  254.     }
  255.  
  256.     Init();
  257.  
  258.     EnterCritSection(m_Sync);
  259.     m_sOptionsCache[nOptionID-1].nType = 1;
  260.     m_sOptionsCache[nOptionID-1].value = value;
  261.     m_sOptionsCache[nOptionID-1].bCached = TRUE;
  262.     m_OptionsCache[nOptionID-1] = m_sOptionsCache[nOptionID-1];
  263.  
  264.     LeaveCritSection(m_Sync);
  265.  
  266.     if (!save)
  267.         return;
  268.  
  269.     CStdString valuestr;
  270.     valuestr.Format( _T("%I64d"), value);
  271.  
  272.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  273.     GetModuleFileName( 0, buffer, MAX_PATH );
  274.     LPTSTR pos=_tcsrchr(buffer, '\\');
  275.     if (pos)
  276.         *++pos=0;
  277.     _tcscat(buffer, _T("FileZilla Server.xml"));
  278.  
  279.     USES_CONVERSION;
  280.     char* bufferA = T2A(buffer);
  281.     if (!bufferA)
  282.         return;
  283.  
  284.     TiXmlDocument document;
  285.     if (!document.LoadFile(bufferA))
  286.         return;
  287.  
  288.     TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer");
  289.     if (!pRoot)
  290.         return;
  291.  
  292.     TiXmlElement* pSettings = pRoot->FirstChildElement("Settings");
  293.     if (!pSettings)
  294.         pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement();
  295.  
  296.     TiXmlElement* pItem;
  297.     for (pItem = pSettings->FirstChildElement("Item"); pItem; pItem = pItem->NextSiblingElement("Item"))
  298.     {
  299.         const char* pName = pItem->Attribute("name");
  300.         if (!pName)
  301.             continue;
  302.         CStdString name(pName);
  303.         if (name != m_Options[nOptionID-1].name)
  304.             continue;
  305.  
  306.         break;
  307.     }
  308.  
  309.     if (!pItem)
  310.         pItem = pSettings->LinkEndChild(new TiXmlElement("Item"))->ToElement();
  311.     pItem->Clear();
  312.     pItem->SetAttribute("name", ConvToNetwork(m_Options[nOptionID-1].name));
  313.     pItem->SetAttribute("type", "numeric");
  314.     pItem->LinkEndChild(new TiXmlText(ConvToNetwork(valuestr)));
  315.     
  316.     document.SaveFile(bufferA);
  317. }
  318.  
  319. void COptions::SetOption(int nOptionID, LPCTSTR value, bool save /*=true*/)
  320. {
  321.     CStdString str = value;
  322.     Init();
  323.  
  324.     switch (nOptionID)
  325.     {
  326.     case OPTION_SERVERPORT:
  327.     case OPTION_SSLPORTS:
  328.         {
  329.             std::set<int> portSet;
  330.             
  331.             str.TrimLeft(_T(" ,"));
  332.  
  333.             int pos = str.FindOneOf(_T(" ,"));
  334.             while (pos != -1)
  335.             {
  336.                 int port = _ttoi(str.Left(pos));
  337.                 if (port >= 1 && port <= 65535)
  338.                     portSet.insert(port);
  339.                 str = str.Mid(pos + 1);
  340.                 str.TrimLeft(_T(" ,"));
  341.                 pos = str.FindOneOf(_T(" ,"));
  342.             }
  343.             if (str != _T(""))
  344.             {
  345.                 int port = _ttoi(str);
  346.                 if (port >= 1 && port <= 65535)
  347.                     portSet.insert(port);
  348.             }
  349.  
  350.             str = _T("");
  351.             for (std::set<int>::const_iterator iter = portSet.begin(); iter != portSet.end(); iter++)
  352.             {
  353.                 CStdString tmp;
  354.                 tmp.Format(_T("%d "), *iter);
  355.                 str += tmp;
  356.             }
  357.             str.TrimRight(' ');
  358.         }
  359.         break;
  360.     case OPTION_WELCOMEMESSAGE:
  361.         {
  362.             std::vector<CStdString> msgLines;
  363.             int oldpos = 0;
  364.             str.Replace(_T("\r\n"), _T("\n"));
  365.             int pos = str.Find(_T("\n"));
  366.             CStdString line;
  367.             while (pos != -1)
  368.             {
  369.                 if (pos)
  370.                 {
  371.                     line = str.Mid(oldpos, pos - oldpos);
  372.                     line = line.Left(CONST_WELCOMEMESSAGE_LINESIZE);
  373.                     line.TrimRight(_T(" "));
  374.                     if (msgLines.size() || line != _T(""))
  375.                         msgLines.push_back(line);
  376.                 }
  377.                 oldpos = pos + 1;
  378.                 pos = str.Find(_T("\n"), oldpos);
  379.             }
  380.             line = str.Mid(oldpos);
  381.             if (line != _T(""))
  382.             {
  383.                 line = line.Left(CONST_WELCOMEMESSAGE_LINESIZE);
  384.                 msgLines.push_back(line);
  385.             }
  386.             str = _T("");
  387.             for (unsigned int i = 0; i < msgLines.size(); i++)
  388.                 str += msgLines[i] + _T("\r\n");
  389.             str.TrimRight(_T("\r\n"));
  390.             if (str == _T(""))
  391.             {
  392.                 str = _T("%v");
  393.                 str += _T("\r\nwritten by Tim Kosse (Tim.Kosse@gmx.de)");
  394.                 str += _T("\r\nPlease visit http://sourceforge.net/projects/filezilla/");
  395.             }
  396.         }
  397.         break;
  398.     case OPTION_ADMINIPBINDINGS:
  399.         {
  400.             CStdString sub;
  401.             std::list<CStdString> ipBindList;
  402.             for (unsigned int i = 0; i<_tcslen(value); i++)
  403.             {
  404.                 TCHAR cur = value[i];
  405.                 if ((cur < '0' || cur > '9') && cur != '.' && cur != ':')
  406.                 {
  407.                     if (sub == _T("") && cur == '*')
  408.                     {
  409.                         ipBindList.clear();
  410.                         ipBindList.push_back(_T("*"));
  411.                         break;
  412.                     }
  413.  
  414.                     if (sub != _T(""))
  415.                     {
  416.                         if (IsIpAddress(sub))
  417.                             ipBindList.push_back(sub);
  418.                         sub = _T("");
  419.                     }
  420.                 }
  421.                 else
  422.                     sub += cur;
  423.             }
  424.             if (sub != _T(""))
  425.             {
  426.                 if (IsIpAddress(sub))
  427.                     ipBindList.push_back(sub);
  428.             }
  429.             str = _T("");
  430.             for (std::list<CStdString>::iterator iter = ipBindList.begin(); iter!=ipBindList.end(); iter++)
  431.                 if (!IsLocalhost(*iter))
  432.                     str += *iter + _T(" ");
  433.  
  434.             str.TrimRight(_T(" "));
  435.         }
  436.         break;
  437.     case OPTION_ADMINPASS:
  438.         if (str != _T("") && str.GetLength() < 6)
  439.             return;
  440.         break;
  441.     case OPTION_MODEZ_DISALLOWED_IPS:
  442.     case OPTION_IPFILTER_ALLOWED:
  443.     case OPTION_IPFILTER_DISALLOWED:
  444.     case OPTION_ADMINIPADDRESSES:
  445.         {
  446.             str.Replace('\r', ' ');
  447.             str.Replace('\n', ' ');
  448.             str.Replace('\r', ' ');
  449.             while (str.Replace(_T("  "), _T(" ")));
  450.             str += _T(" ");
  451.  
  452.             CStdString ips;
  453.  
  454.             int pos = str.Find(' ');
  455.             while (pos != -1)
  456.             {
  457.                 CStdString sub = str.Left(pos);
  458.                 str = str.Mid(pos + 1);
  459.                 str.TrimLeft(' ');
  460.  
  461.                 if (sub == _T("*"))
  462.                     ips += _T(" ") + sub;
  463.                 else
  464.                 {
  465.                     if (IsValidAddressFilter(sub))
  466.                         ips += " " + sub;
  467.                     pos = str.Find(' ');
  468.                 }
  469.             }
  470.             ips.TrimLeft(' ');
  471.  
  472.             str = ips;
  473.         }
  474.         break;
  475.     case OPTION_IPBINDINGS:
  476.         {
  477.             CStdString sub;
  478.             std::list<CStdString> ipBindList;
  479.             for (unsigned int i = 0; i<_tcslen(value); i++)
  480.             {
  481.                 TCHAR cur = value[i];
  482.                 if ((cur < '0' || cur > '9') && cur != '.' && cur != ':')
  483.                 {
  484.                     if (sub == _T("") && cur == '*')
  485.                     {
  486.                         ipBindList.clear();
  487.                         ipBindList.push_back(_T("*"));
  488.                         break;
  489.                     }
  490.  
  491.                     if (sub != _T(""))
  492.                     {
  493.                         if (IsIpAddress(sub))
  494.                             ipBindList.push_back(sub);
  495.                         sub = _T("");
  496.                     }
  497.                 }
  498.                 else
  499.                     sub += cur;
  500.             }
  501.             if (sub != _T(""))
  502.             {
  503.                 if (IsIpAddress(sub))
  504.                     ipBindList.push_back(sub);
  505.             }
  506.  
  507.             if (ipBindList.empty())
  508.                 ipBindList.push_back(_T("*"));
  509.  
  510.             str = _T("");
  511.             for (std::list<CStdString>::iterator iter = ipBindList.begin(); iter != ipBindList.end(); iter++)
  512.                 str += *iter + _T(" ");
  513.  
  514.             str.TrimRight(_T(" "));
  515.         }
  516.         break;
  517.     case OPTION_CUSTOMPASVIPSERVER:
  518.         if (str.Find(_T("filezilla.sourceforge.net")) != -1)
  519.             str = _T("http://ip.filezilla-project.org/ip.php");
  520.         break;
  521.     }
  522.     EnterCritSection(m_Sync);
  523.     m_sOptionsCache[nOptionID-1].bCached = TRUE;
  524.     m_sOptionsCache[nOptionID-1].nType = 0;
  525.     m_sOptionsCache[nOptionID-1].str = str;
  526.     m_OptionsCache[nOptionID-1]=m_sOptionsCache[nOptionID-1];
  527.     LeaveCritSection(m_Sync);
  528.  
  529.     if (!save)
  530.         return;
  531.  
  532.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  533.     GetModuleFileName( 0, buffer, MAX_PATH );
  534.     LPTSTR pos=_tcsrchr(buffer, '\\');
  535.     if (pos)
  536.         *++pos=0;
  537.     _tcscat(buffer, _T("FileZilla Server.xml"));
  538.  
  539. USES_CONVERSION;
  540.     char* bufferA = T2A(buffer);
  541.     if (!bufferA)
  542.         return;
  543.  
  544.     TiXmlDocument document;
  545.     if (!document.LoadFile(bufferA))
  546.         return;
  547.  
  548.     TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer");
  549.     if (!pRoot)
  550.         return;
  551.  
  552.     TiXmlElement* pSettings = pRoot->FirstChildElement("Settings");
  553.     if (!pSettings)
  554.         pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement();
  555.  
  556.     TiXmlElement* pItem;
  557.     for (pItem = pSettings->FirstChildElement("Item"); pItem; pItem = pItem->NextSiblingElement("Item"))
  558.     {
  559.         const char* pName = pItem->Attribute("name");
  560.         if (!pName)
  561.             continue;
  562.         CStdString name(pName);
  563.         if (name != m_Options[nOptionID-1].name)
  564.             continue;
  565.  
  566.         break;
  567.     }
  568.  
  569.     if (!pItem)
  570.         pItem = pSettings->LinkEndChild(new TiXmlElement("Item"))->ToElement();
  571.     pItem->Clear();
  572.     pItem->SetAttribute("name", ConvToNetwork(m_Options[nOptionID-1].name));
  573.     pItem->SetAttribute("type", "string");
  574.     pItem->LinkEndChild(new TiXmlText(ConvToNetwork(value)));
  575.     
  576.     document.SaveFile(bufferA);
  577. }
  578.  
  579. CStdString COptions::GetOption(int nOptionID)
  580. {
  581.     ASSERT(nOptionID>0 && nOptionID<=OPTIONS_NUM);
  582.     ASSERT(!m_Options[nOptionID-1].nType);
  583.     Init();
  584.  
  585.     if (m_OptionsCache[nOptionID-1].bCached)
  586.         return m_OptionsCache[nOptionID-1].str;
  587.  
  588.     EnterCritSection(m_Sync);
  589.  
  590.     if (!m_sOptionsCache[nOptionID-1].bCached)
  591.     {
  592.         //Default values
  593.         switch (nOptionID)
  594.         {
  595.         case OPTION_SERVERPORT:
  596.             m_sOptionsCache[nOptionID-1].str = _T("21");
  597.             break;
  598.         case OPTION_WELCOMEMESSAGE:
  599.             m_sOptionsCache[nOptionID-1].str = _T("%v");
  600.             m_sOptionsCache[nOptionID-1].str += _T("\r\nwritten by Tim Kosse (Tim.Kosse@gmx.de)");
  601.             m_sOptionsCache[nOptionID-1].str += _T("\r\nPlease visit http://sourceforge.net/projects/filezilla/");
  602.             break;
  603.         case OPTION_CUSTOMPASVIPSERVER:
  604.             m_sOptionsCache[nOptionID-1].str = _T("http://ip.filezilla-project.org/ip.php");
  605.             break;
  606.         case OPTION_IPBINDINGS:
  607.             m_sOptionsCache[nOptionID-1].str = _T("*");
  608.             break;
  609.         case OPTION_SSLPORTS:
  610.             m_sOptionsCache[nOptionID-1].str = _T("990");
  611.             break;
  612.         default:
  613.             m_sOptionsCache[nOptionID-1].str = _T("");
  614.             break;
  615.         }
  616.         m_sOptionsCache[nOptionID-1].bCached = TRUE;
  617.         m_sOptionsCache[nOptionID-1].nType = 0;
  618.     }
  619.     m_OptionsCache[nOptionID-1] = m_sOptionsCache[nOptionID - 1];
  620.     LeaveCritSection(m_Sync);
  621.     return m_OptionsCache[nOptionID-1].str;
  622. }
  623.  
  624. _int64 COptions::GetOptionVal(int nOptionID)
  625. {
  626.     ASSERT(nOptionID>0 && nOptionID<=OPTIONS_NUM);
  627.     ASSERT(m_Options[nOptionID-1].nType == 1);
  628.     Init();
  629.  
  630.     if (m_OptionsCache[nOptionID-1].bCached)
  631.         return m_OptionsCache[nOptionID-1].value;
  632.  
  633.     EnterCritSection(m_Sync);
  634.  
  635.     if (!m_sOptionsCache[nOptionID-1].bCached)
  636.     {
  637.         //Default values
  638.         switch (nOptionID)
  639.         {
  640.             case OPTION_MAXUSERS:
  641.                 m_sOptionsCache[nOptionID-1].value = 0;
  642.                 break;
  643.             case OPTION_THREADNUM:
  644.                 m_sOptionsCache[nOptionID-1].value = 2;
  645.                 break;
  646.             case OPTION_TIMEOUT:
  647.             case OPTION_NOTRANSFERTIMEOUT:
  648.                 m_sOptionsCache[nOptionID-1].value = 120;
  649.                 break;
  650.             case OPTION_LOGINTIMEOUT:
  651.                 m_sOptionsCache[nOptionID-1].value = 60;
  652.                 break;
  653.             case OPTION_ADMINPORT:
  654.                 m_sOptionsCache[nOptionID-1].value = 14147;
  655.                 break;
  656.             case OPTION_DOWNLOADSPEEDLIMIT:
  657.             case OPTION_UPLOADSPEEDLIMIT:
  658.                 m_sOptionsCache[nOptionID-1].value = 10;
  659.                 break;
  660.             case OPTION_BUFFERSIZE:
  661.                 m_sOptionsCache[nOptionID-1].value = 32768;
  662.                 break;
  663.             case OPTION_CUSTOMPASVIPTYPE:
  664.                 m_sOptionsCache[nOptionID-1].value = 0;
  665.                 break;
  666.             case OPTION_MODEZ_USE:
  667.                 m_sOptionsCache[nOptionID-1].value = 0;
  668.                 break;
  669.             case OPTION_MODEZ_LEVELMIN:
  670.                 m_sOptionsCache[nOptionID-1].value = 1;
  671.                 break;
  672.             case OPTION_MODEZ_LEVELMAX:
  673.                 m_sOptionsCache[nOptionID-1].value = 9;
  674.                 break;
  675.             case OPTION_MODEZ_ALLOWLOCAL:
  676.                 m_sOptionsCache[nOptionID-1].value = 0;
  677.                 break;
  678.             case OPTION_ALLOWEXPLICITSSL:
  679.                 m_sOptionsCache[nOptionID-1].value = 1;
  680.                 break;
  681.             case OPTION_BUFFERSIZE2:
  682.                 m_sOptionsCache[nOptionID-1].value = 65536;
  683.                 break;
  684.             case OPTION_NOEXTERNALIPONLOCAL:
  685.                 m_sOptionsCache[nOptionID-1].value = 1;
  686.                 break;
  687.             case OPTION_ACTIVE_IGNORELOCAL:
  688.                 m_sOptionsCache[nOptionID-1].value = 1;
  689.                 break;
  690.             case OPTION_AUTOBAN_BANTIME:
  691.                 m_sOptionsCache[nOptionID-1].value = 1;
  692.                 break;
  693.             case OPTION_AUTOBAN_ATTEMPTS:
  694.                 m_sOptionsCache[nOptionID-1].value = 10;
  695.                 break;
  696.             default:
  697.                 m_sOptionsCache[nOptionID-1].value = 0;
  698.         }
  699.         m_sOptionsCache[nOptionID-1].bCached=TRUE;
  700.         m_sOptionsCache[nOptionID-1].nType=1;
  701.     }
  702.     m_OptionsCache[nOptionID-1]=m_sOptionsCache[nOptionID-1];
  703.     LeaveCritSection(m_Sync);
  704.     return m_OptionsCache[nOptionID-1].value;
  705. }
  706.  
  707. void COptions::UpdateInstances()
  708. {
  709.     EnterCritSection(m_Sync);
  710.     for (std::list<COptions *>::iterator iter=m_InstanceList.begin(); iter!=m_InstanceList.end(); iter++)
  711.     {
  712.         ASSERT((*iter)->m_pOptionsHelperWindow);
  713.         ::PostMessage((*iter)->m_pOptionsHelperWindow->GetHwnd(), WM_USER, 0, 0);
  714.     }
  715.     LeaveCritSection(m_Sync);
  716. }
  717.  
  718. void COptions::Init()
  719. {
  720.     if (m_bInitialized)
  721.         return;
  722.     EnterCritSection(m_Sync);
  723.     m_bInitialized = TRUE;
  724.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  725.     GetModuleFileName( 0, buffer, MAX_PATH );
  726.     LPTSTR pos=_tcsrchr(buffer, '\\');
  727.     if (pos)
  728.         *++pos=0;
  729.     _tcscat(buffer, _T("FileZilla Server.xml"));
  730.  
  731.     for (int i = 0; i < OPTIONS_NUM; i++)
  732.         m_sOptionsCache[i].bCached = FALSE;
  733.  
  734.     USES_CONVERSION;
  735.     char* bufferA = T2A(buffer);
  736.     if (!bufferA)
  737.     {
  738.         LeaveCritSection(m_Sync);
  739.         return;
  740.     }
  741.  
  742.     TiXmlDocument document;
  743.  
  744.     CFileStatus64 status;
  745.     if (!GetStatus64(buffer, status) )
  746.     {
  747.         document.LinkEndChild(new TiXmlElement("FileZillaServer"));
  748.         document.SaveFile(bufferA);
  749.     }
  750.     else if (status.m_attribute & FILE_ATTRIBUTE_DIRECTORY)
  751.     {
  752.         LeaveCritSection(m_Sync);
  753.         return;
  754.     }
  755.  
  756.     if (!document.LoadFile(bufferA))
  757.     {
  758.         LeaveCritSection(m_Sync);
  759.         return;
  760.     }
  761.  
  762.     TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer");
  763.     if (!pRoot)
  764.     {
  765.         LeaveCritSection(m_Sync);
  766.         return;
  767.     }
  768.  
  769.     TiXmlElement* pSettings = pRoot->FirstChildElement("Settings");
  770.     if (!pSettings)
  771.         pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement();
  772.  
  773.     TiXmlElement* pItem;
  774.     for (pItem = pSettings->FirstChildElement("Item"); pItem; pItem = pItem->NextSiblingElement("Item"))
  775.     {
  776.         const char* pName = pItem->Attribute("name");
  777.         if (!pName)
  778.             continue;
  779.         CStdString name(pName);
  780.  
  781.         const char* pType = pItem->Attribute("type");
  782.         if (!pType)
  783.             continue;
  784.         CStdString type(pType);
  785.  
  786.         TiXmlNode* textNode = pItem->FirstChild();
  787.         CStdString value;
  788.         if (textNode && textNode->ToText())
  789.             value = ConvFromNetwork(textNode->Value());
  790.         else if (type == _T("numeric"))
  791.             continue;
  792.  
  793.         for (int i = 0; i < OPTIONS_NUM; i++)
  794.         {
  795.             if (!_tcscmp(name, m_Options[i].name))
  796.             {
  797.                 if (m_sOptionsCache[i].bCached)
  798.                     break;
  799.  
  800.                 if (type == _T("numeric"))
  801.                 {
  802.                     if (m_Options[i].nType != 1)
  803.                         break;
  804.                     _int64 value64 = _ttoi64(value);
  805.                     if (IsNumeric(value))
  806.                         SetOption(i + 1, value64, false);
  807.                 }
  808.                 else
  809.                 {
  810.                     if (m_Options[i].nType != 0)
  811.                         break;
  812.                     SetOption(i + 1, value, false);
  813.                 }
  814.                 break;
  815.             }
  816.         }
  817.     }
  818.     ReadSpeedLimits(pSettings);
  819.  
  820.     LeaveCritSection(m_Sync);
  821.     UpdateInstances();
  822.     return;
  823. }
  824.  
  825. bool COptions::IsNumeric(LPCTSTR str)
  826. {
  827.     if (!str)
  828.         return false;
  829.     LPCTSTR p=str;
  830.     while(*p)
  831.     {
  832.         if (*p<'0' || *p>'9')
  833.         {
  834.             return false;
  835.         }
  836.         p++;
  837.     }
  838.     return true;
  839. }
  840.  
  841. TiXmlElement *COptions::GetXML()
  842. {
  843.     EnterCritSection(m_Sync);
  844.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  845.     GetModuleFileName( 0, buffer, MAX_PATH );
  846.     LPTSTR pos=_tcsrchr(buffer, '\\');
  847.     if (pos)
  848.         *++pos=0;
  849.     _tcscat(buffer, _T("FileZilla Server.xml"));
  850.  
  851.     USES_CONVERSION;
  852.     char* bufferA = T2A(buffer);
  853.     if (!bufferA)
  854.     {
  855.         LeaveCritSection(m_Sync);
  856.         return 0;
  857.     }
  858.  
  859.     TiXmlDocument *pDocument = new TiXmlDocument;
  860.     
  861.     if (!pDocument->LoadFile(bufferA))
  862.     {
  863.         LeaveCritSection(m_Sync);
  864.         delete pDocument;
  865.         return NULL;
  866.     }
  867.  
  868.     TiXmlElement* pElement = pDocument->FirstChildElement("FileZillaServer");
  869.     if (!pElement)
  870.     {
  871.         LeaveCritSection(m_Sync);
  872.         delete pDocument;
  873.         return NULL;
  874.     }
  875.  
  876.     return pElement;
  877. }
  878.  
  879. BOOL COptions::FreeXML(TiXmlElement *pXML, bool save)
  880. {
  881.     ASSERT(pXML);
  882.     if (!pXML)
  883.         return FALSE;
  884.  
  885.     if (!save)
  886.     {
  887.         delete pXML->GetDocument();
  888.         LeaveCritSection(m_Sync);
  889.         return FALSE;
  890.     }
  891.  
  892.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  893.     GetModuleFileName( 0, buffer, MAX_PATH );
  894.     LPTSTR pos=_tcsrchr(buffer, '\\');
  895.     if (pos)
  896.         *++pos=0;
  897.     _tcscat(buffer, _T("FileZilla Server.xml"));
  898.  
  899.     USES_CONVERSION;
  900.     char* bufferA = T2A(buffer);
  901.     if (!bufferA)
  902.     {
  903.         delete pXML->GetDocument();
  904.         LeaveCritSection(m_Sync);
  905.         return FALSE;
  906.     }
  907.  
  908.     if (!pXML->GetDocument()->SaveFile(bufferA))
  909.     {
  910.         delete pXML->GetDocument();
  911.         LeaveCritSection(m_Sync);
  912.         return FALSE;
  913.     }
  914.  
  915.     delete pXML->GetDocument();
  916.     LeaveCritSection(m_Sync);
  917.     return TRUE;
  918. }
  919.  
  920. BOOL COptions::GetAsCommand(char **pBuffer, DWORD *nBufferLength)
  921. {
  922.     int i;
  923.     DWORD len = 2;
  924.  
  925.     EnterCritSection(m_Sync);
  926.     for (i=0; i<OPTIONS_NUM; i++)
  927.     {
  928.         len+=1;
  929.         if (!m_Options[i].nType)
  930.         {
  931.             len += 3;
  932.             char* utf8 = ConvToNetwork(GetOption(i + 1));
  933.             if (utf8)
  934.             {
  935.                 if ((i+1) != OPTION_ADMINPASS)
  936.                     len += strlen(utf8);
  937.                 else
  938.                 {
  939.                     if (GetOption(i+1).GetLength() < 6 && *utf8)
  940.                         len++;
  941.                 }
  942.                 delete [] utf8;
  943.             }
  944.         }
  945.         else
  946.             len+=8;
  947.     }
  948.  
  949.     len += 4;
  950.     SPEEDLIMITSLIST::const_iterator iter;
  951.     for (i = 0; i < 2; i++)
  952.         for (iter = m_sSpeedLimits[i].begin(); iter != m_sSpeedLimits[i].end(); iter++)
  953.             len += iter->GetRequiredBufferLen();
  954.  
  955.     *pBuffer=new char[len];
  956.     char *p=*pBuffer;
  957.     *p++ = OPTIONS_NUM/256;
  958.     *p++ = OPTIONS_NUM%256;
  959.     for (i=0; i<OPTIONS_NUM; i++)
  960.     {
  961.         *p++ = m_Options[i].nType;
  962.         switch(m_Options[i].nType) {
  963.         case 0:
  964.             {
  965.                 CStdString str = GetOption(i+1);
  966.                 if ((i+1)==OPTION_ADMINPASS) //Do NOT send admin password,
  967.                                              //instead send empty string if admin pass is set
  968.                                              //and send a single char if admin pass is invalid (len < 6)
  969.                 {
  970.                     if (str.GetLength() >= 6 || str == _T(""))
  971.                         str = _T("");
  972.                     else
  973.                         str = _T("*");
  974.                 }
  975.  
  976.                 char* utf8 = ConvToNetwork(str);
  977.                 if (!utf8)
  978.                 {
  979.                     *p++ = 0;
  980.                     *p++ = 0;
  981.                     *p++ = 0;
  982.                 }
  983.                 else
  984.                 {
  985.                     int len = strlen(utf8);
  986.                     *p++ = (len / 256) / 256;
  987.                     *p++ = len / 256;
  988.                     *p++ = len % 256;
  989.                     memcpy(p, utf8, len);
  990.                     p += len;
  991.                     delete [] utf8;
  992.                 }
  993.             }
  994.             break;
  995.         case 1:
  996.             {
  997.                 _int64 value = GetOptionVal(i+1);
  998.                 memcpy(p, &value, 8);
  999.                 p+=8;
  1000.             }
  1001.             break;
  1002.         default:
  1003.             ASSERT(FALSE);
  1004.         }
  1005.     }
  1006.  
  1007.     for (i = 0; i < 2; i++)
  1008.     {
  1009.         *p++ = m_sSpeedLimits[i].size() << 8;
  1010.         *p++ = m_sSpeedLimits[i].size() %256;
  1011.         for (iter = m_sSpeedLimits[i].begin(); iter != m_sSpeedLimits[i].end(); iter++)
  1012.             p = iter->FillBuffer(p);
  1013.     }
  1014.  
  1015.     LeaveCritSection(m_Sync);
  1016.  
  1017.     *nBufferLength = len;
  1018.  
  1019.     return TRUE;
  1020. }
  1021.  
  1022. BOOL COptions::ParseOptionsCommand(unsigned char *pData, DWORD dwDataLength, BOOL bFromLocal /*=FALSE*/)
  1023. {
  1024.     unsigned char *p = pData;
  1025.     int num = *p * 256 + p[1];
  1026.     p+=2;
  1027.     if (num!=OPTIONS_NUM)
  1028.         return FALSE;
  1029.  
  1030.     int i;
  1031.     for (i = 0; i < num; i++)
  1032.     {
  1033.         if ((DWORD)(p-pData)>=dwDataLength)
  1034.             return FALSE;
  1035.         int nType = *p++;
  1036.         if (!nType)
  1037.         {
  1038.             if ((DWORD)(p-pData+3) >= dwDataLength)
  1039.                 return 2;
  1040.             int len = *p * 256 * 256 + p[1] * 256 + p[2];
  1041.             p += 3;
  1042.             if ((DWORD)(p - pData + len) > dwDataLength)
  1043.                 return FALSE;
  1044.             char *pBuffer = new char[len + 1];
  1045.             memcpy(pBuffer, p, len);
  1046.             pBuffer[len]=0;
  1047.             if (!m_Options[i].bOnlyLocal || bFromLocal) //Do not change admin interface settings from remote connections
  1048. #ifdef _UNICODE
  1049.                 SetOption(i+1, ConvFromNetwork(pBuffer), false);
  1050. #else
  1051.                 SetOption(i+1, ConvToLocal(ConvFromNetwork(pBuffer)), false);
  1052. #endif
  1053.             delete [] pBuffer;
  1054.             p+=len;
  1055.         }
  1056.         else if (nType == 1)
  1057.         {
  1058.             if ((DWORD)(p-pData+8)>dwDataLength)
  1059.                 return FALSE;
  1060.             if (!m_Options[i].bOnlyLocal || bFromLocal) //Do not change admin interface settings from remote connections
  1061.                 SetOption(i+1, GET64(p), false);
  1062.             p+=8;
  1063.         }
  1064.         else
  1065.             return FALSE;
  1066.     }
  1067.  
  1068.     SPEEDLIMITSLIST dl;
  1069.     SPEEDLIMITSLIST ul;
  1070.  
  1071.     if ((DWORD)(p-pData+2)>dwDataLength)
  1072.         return FALSE;
  1073.     num = *p++ << 8;
  1074.     num |= *p++;
  1075.     EnterCritSection(m_Sync);
  1076.     for (i=0; i<num; i++)
  1077.     {
  1078.         CSpeedLimit limit;
  1079.         p = limit.ParseBuffer(p, dwDataLength - (p - pData));
  1080.         if (!p)
  1081.         {
  1082.             LeaveCritSection(m_Sync);
  1083.             return FALSE;
  1084.         }
  1085.         dl.push_back(limit);
  1086.     }
  1087.  
  1088.     if ((DWORD)(p-pData+2)>dwDataLength)
  1089.     {
  1090.         LeaveCritSection(m_Sync);
  1091.         return FALSE;
  1092.     }
  1093.     num = *p++ << 8;
  1094.     num |= *p++;
  1095.     for (i=0; i<num; i++)
  1096.     {
  1097.         CSpeedLimit limit;
  1098.         p = limit.ParseBuffer(p, dwDataLength - (p - pData));
  1099.         if (!p)
  1100.         {
  1101.             LeaveCritSection(m_Sync);
  1102.             return FALSE;
  1103.         }
  1104.         ul.push_back(limit);
  1105.     }
  1106.  
  1107.     m_sSpeedLimits[0] = dl;
  1108.     m_sSpeedLimits[1] = ul;
  1109.  
  1110.     SaveOptions();
  1111.  
  1112.     LeaveCritSection(m_Sync);
  1113.  
  1114.     UpdateInstances();
  1115.  
  1116.     return TRUE;
  1117. }
  1118.  
  1119. static void SetText(TiXmlElement* pElement, const CStdString& text)
  1120. {
  1121.     pElement->Clear();
  1122.     pElement->LinkEndChild(new TiXmlText(ConvToNetwork(text)));
  1123. }
  1124.  
  1125. BOOL COptions::SaveSpeedLimits(TiXmlElement* pSettings)
  1126. {
  1127.     TiXmlElement* pSpeedLimits;
  1128.     while ((pSpeedLimits = pSettings->FirstChildElement("SpeedLimits")))
  1129.         pSettings->RemoveChild(pSpeedLimits);
  1130.     
  1131.     pSpeedLimits = pSettings->LinkEndChild(new TiXmlElement("SpeedLimits"))->ToElement();
  1132.  
  1133.     const char* names[] = { "Download", "Upload" };
  1134.  
  1135.     for (int i = 0; i < 2; i++)
  1136.     {
  1137.         TiXmlElement* pSpeedLimit = new TiXmlElement(names[i]);
  1138.         pSpeedLimits->LinkEndChild(pSpeedLimit);
  1139.  
  1140.         for (unsigned int j = 0; j < m_sSpeedLimits[i].size(); j++)
  1141.         {
  1142.             CSpeedLimit limit = m_sSpeedLimits[i][j];
  1143.  
  1144.             TiXmlElement* pRule = pSpeedLimit->LinkEndChild(new TiXmlElement("Rule"))->ToElement();
  1145.             limit.Save(pRule);
  1146.         }
  1147.     }
  1148.  
  1149.     return TRUE;
  1150. }
  1151.  
  1152. CStdString ReadText(TiXmlElement* pElement)
  1153. {
  1154.     TiXmlNode* textNode = pElement->FirstChild();
  1155.     if (!textNode || !textNode->ToText())
  1156.         return _T("");
  1157.  
  1158.     return ConvFromNetwork(textNode->Value());                    
  1159. }
  1160.  
  1161. BOOL COptions::ReadSpeedLimits(TiXmlElement *pXML)
  1162. {
  1163.     const char* names[] = { "Download", "Upload" };
  1164.  
  1165.     for (int i = 0; i < 2; i++)
  1166.     {
  1167.         for (TiXmlElement* pSpeedLimits = pXML->FirstChildElement("SpeedLimits"); pSpeedLimits; pSpeedLimits = pSpeedLimits->NextSiblingElement("SpeedLimits"))
  1168.         {
  1169.             for (TiXmlElement* pLimit = pSpeedLimits->FirstChildElement(names[i]); pLimit; pLimit = pLimit->NextSiblingElement(names[i]))
  1170.             {
  1171.                 for (TiXmlElement* pRule = pLimit->FirstChildElement("Rule"); pRule; pRule = pRule->NextSiblingElement("Rule"))
  1172.                 {
  1173.                     CSpeedLimit limit;
  1174.                     if (!limit.Load(pRule))
  1175.                         continue;
  1176.  
  1177.                     if (m_sSpeedLimits[i].size() < 20000)
  1178.                         m_sSpeedLimits[i].push_back(limit);
  1179.                 }
  1180.             }
  1181.         }
  1182.     }
  1183.     
  1184.     return TRUE;
  1185. }
  1186.  
  1187. int COptions::GetCurrentSpeedLimit(int nMode)
  1188. {
  1189.     Init();
  1190.  
  1191.     int type[2] = { OPTION_DOWNLOADSPEEDLIMITTYPE, OPTION_UPLOADSPEEDLIMITTYPE };
  1192.     int limit[2] = { OPTION_DOWNLOADSPEEDLIMIT, OPTION_UPLOADSPEEDLIMIT };
  1193.  
  1194.     int nType = (int)GetOptionVal(type[nMode]);
  1195.     switch (nType)
  1196.     {
  1197.     case 0:
  1198.         return -1;
  1199.     case 1:
  1200.         return (int)GetOptionVal(limit[nMode]);
  1201.     default:
  1202.         {
  1203.             SYSTEMTIME s;
  1204.             GetLocalTime(&s);
  1205.             for (SPEEDLIMITSLIST::const_iterator iter = m_SpeedLimits[nMode].begin(); iter != m_SpeedLimits[nMode].end(); iter++)
  1206.                 if (iter->IsItActive(s))
  1207.                     return iter->m_Speed;
  1208.             return -1;
  1209.         }
  1210.     }
  1211. }
  1212.  
  1213. void COptions::ReloadConfig()
  1214. {
  1215.     EnterCritSection(m_Sync);
  1216.  
  1217.     m_bInitialized = TRUE;
  1218.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  1219.     GetModuleFileName( 0, buffer, MAX_PATH );
  1220.     LPTSTR pos = _tcsrchr(buffer, '\\');
  1221.     if (pos)
  1222.         *++pos = 0;
  1223.     _tcscat(buffer, _T("FileZilla Server.xml"));
  1224.  
  1225.     for (int i = 0; i < OPTIONS_NUM; i++)
  1226.         m_sOptionsCache[i].bCached = FALSE;
  1227.  
  1228.     USES_CONVERSION;
  1229.     char* bufferA = T2A(buffer);
  1230.     if (!bufferA)
  1231.     {
  1232.         LeaveCritSection(m_Sync);
  1233.         return;
  1234.     }
  1235.  
  1236.     TiXmlDocument document;
  1237.  
  1238.     CFileStatus64 status;
  1239.     if (!GetStatus64(buffer, status) )
  1240.     {
  1241.         document.LinkEndChild(new TiXmlElement("FileZillaServer"));
  1242.         document.SaveFile(bufferA);
  1243.     }
  1244.     else if (status.m_attribute & FILE_ATTRIBUTE_DIRECTORY)
  1245.     {
  1246.         LeaveCritSection(m_Sync);
  1247.         return;
  1248.     }
  1249.  
  1250.     if (!document.LoadFile(bufferA))
  1251.     {
  1252.         LeaveCritSection(m_Sync);
  1253.         return;
  1254.     }
  1255.  
  1256.     TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer");
  1257.     if (!pRoot)
  1258.     {
  1259.         LeaveCritSection(m_Sync);
  1260.         return;
  1261.     }
  1262.  
  1263.     TiXmlElement* pSettings = pRoot->FirstChildElement("Settings");
  1264.     if (!pSettings)
  1265.         pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement();
  1266.  
  1267.     TiXmlElement* pItem;
  1268.     for (pItem = pSettings->FirstChildElement("Item"); pItem; pItem = pItem->NextSiblingElement("Item"))
  1269.     {
  1270.         const char* pName = pItem->Attribute("name");
  1271.         if (!pName)
  1272.             continue;
  1273.         CStdString name(pName);
  1274.         const char* pType = pItem->Attribute("type");
  1275.         if (!pType)
  1276.             continue;
  1277.         CStdString type(pType);
  1278.         TiXmlNode* textNode = pItem->FirstChild();
  1279.         if (!textNode || !textNode->ToText())
  1280.             continue;
  1281.         CStdString value = ConvFromNetwork(textNode->Value());
  1282.  
  1283.  
  1284.         for (int i = 0;i < OPTIONS_NUM; i++)
  1285.         {
  1286.             if (!_tcscmp(name, m_Options[i].name))
  1287.             {
  1288.                 if (m_sOptionsCache[i].bCached)
  1289.                     break;
  1290.  
  1291.                 if (type == _T("numeric"))
  1292.                 {
  1293.                     if (m_Options[i].nType != 1)
  1294.                         break;
  1295.                     _int64 value64 = _ttoi64(value);
  1296.                     if (IsNumeric(value))
  1297.                         SetOption(i + 1, value64, false);
  1298.                 }
  1299.                 else
  1300.                 {
  1301.                     if (m_Options[i].nType != 0)
  1302.                         break;
  1303.                     SetOption(i  +1, value, false);
  1304.                 }
  1305.                 break;
  1306.             }
  1307.         }
  1308.     }
  1309.     ReadSpeedLimits(pSettings);
  1310.  
  1311.     LeaveCritSection(m_Sync);
  1312.     UpdateInstances();
  1313. }
  1314.  
  1315. void COptions::SaveOptions()
  1316. {
  1317.     TCHAR buffer[MAX_PATH + 1000]; //Make it large enough
  1318.     GetModuleFileName( 0, buffer, MAX_PATH );
  1319.     LPTSTR pos=_tcsrchr(buffer, '\\');
  1320.     if (pos)
  1321.         *++pos=0;
  1322.     _tcscat(buffer, _T("FileZilla Server.xml"));
  1323.  
  1324.     USES_CONVERSION;
  1325.     char* bufferA = T2A(buffer);
  1326.     if (!bufferA)
  1327.         return;
  1328.  
  1329.     TiXmlDocument document;
  1330.     if (!document.LoadFile(bufferA))
  1331.         return;
  1332.  
  1333.     TiXmlElement* pRoot = document.FirstChildElement("FileZillaServer");
  1334.     if (!pRoot)
  1335.         return;
  1336.  
  1337.     TiXmlElement* pSettings;
  1338.     while ((pSettings = pRoot->FirstChildElement("Settings")))
  1339.         pRoot->RemoveChild(pSettings);
  1340.     pSettings = pRoot->LinkEndChild(new TiXmlElement("Settings"))->ToElement();
  1341.  
  1342.     for (unsigned int i = 0; i < OPTIONS_NUM; i++)
  1343.     {
  1344.         if (!m_OptionsCache[i].bCached)
  1345.             continue;
  1346.  
  1347.         CStdString valuestr;
  1348.         if (!m_OptionsCache[i].nType)
  1349.             valuestr = m_OptionsCache[i].str;
  1350.         else
  1351.             valuestr.Format( _T("%I64d"), m_OptionsCache[i].value);
  1352.  
  1353.         TiXmlElement* pItem = pSettings->LinkEndChild(new TiXmlElement("Item"))->ToElement();
  1354.         pItem->SetAttribute("name", ConvToNetwork(m_Options[i].name));
  1355.         if (!m_OptionsCache[i].nType)
  1356.             pItem->SetAttribute("type", "string");
  1357.         else
  1358.             pItem->SetAttribute("type", "numeric");
  1359.         pItem->LinkEndChild(new TiXmlText(ConvToNetwork(valuestr)));
  1360.     }
  1361.  
  1362.     SaveSpeedLimits(pSettings);
  1363.  
  1364.     document.SaveFile(bufferA);
  1365. }
  1366.